/*
 * Wazuh Vulnerability scanner
 * Copyright (C) 2015, Wazuh Inc.
 * March 25, 2023.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#ifndef _VULNERABILITY_SCANNER_FACADE_HPP
#define _VULNERABILITY_SCANNER_FACADE_HPP

#include "databaseFeedManager/databaseFeedManager.hpp"
#include "defs.h"
#include "indexerConnector.hpp"
#include "logging_helper.h"
#include "policyManager/policyManager.hpp"
#include "routerSubscriber.hpp"
#include "scanOrchestrator/scanOrchestrator.hpp"
#include "singleton.hpp"
#include "socketClient.hpp"
#include <atomic>
#include <functional>
#include <memory>
#include <string>
#include <vector>

using DelayedEventDispatcher = TThreadEventDispatcher<rocksdb::Slice,
                                                      rocksdb::PinnableSlice,
                                                      std::function<void(std::queue<rocksdb::PinnableSlice>&)>>;

/**
 * @brief VulnerabilityScannerFacade class.
 *
 */
class VulnerabilityScannerFacade final : public Singleton<VulnerabilityScannerFacade>
{
public:
    /**
     * @brief Starts facade.
     *
     * @param logFunction Log function.
     * @param configuration Facade configuration.
     * @param noWaitToStop If true, the facade will not wait to stop if any process is running.
     * @param reloadGlobalMapsStartup If true, the global maps will be reloaded at startup of the database feed manager.
     * @param initContentUpdater If true, the content updater will be initialized.
     */
    void start(const std::function<void(const int,
                                        const std::string&,
                                        const std::string&,
                                        const int,
                                        const std::string&,
                                        const std::string&,
                                        va_list)>& logFunction,
               const nlohmann::json& configuration,
               bool noWaitToStop = true,
               bool reloadGlobalMapsStartup = true,
               bool initContentUpdater = true);

    /**
     * @brief Stops facade.
     *
     */
    void stop();

    /**
     * @brief Decompress database content.
     *
     * @param databaseVersion Current database version.
     * @return true if the decompression was sucesfull.
     */
    bool decompressDatabase(const std::string& databaseVersion);

    /**
     * @brief Initializes the alert report dispatcher.
     *
     */
    void initAlertReportDispatcher();

    /**
     * @brief Initializes the delayed events dispatcher.
     *
     * @param scanOrchestrator Scan orchestrator.
     */
    void initDelayedEventsDispatcher(std::shared_ptr<ScanOrchestrator> scanOrchestrator);

    /**
     * @brief Initializes the rsync subscription.
     *
     * @param scanOrchestrator Scan orchestrator.
     */
    void initRsyncSubscription(std::shared_ptr<ScanOrchestrator> scanOrchestrator);

    /**
     * @brief Initializes the deltas subscription.
     *
     * @param scanOrchestrator Scan orchestrator.
     */
    void initDeltasSubscription(std::shared_ptr<ScanOrchestrator> scanOrchestrator);

    /** @brief Initializes the Wazuh DB event subscription.
     *
     * @param scanOrchestrator Scan orchestrator.
     */
    void initWazuhDBEventSubscription(std::shared_ptr<ScanOrchestrator> scanOrchestrator);

    /**
     * @brief Rescan if VD policy change from false to true.
     * This method is used to initialize the rescan dispatcher if vulnerability detection is enabled.
     *
     * @param scanOrchestrator Scan orchestrator.
     */
    void vulnerabilityScannerPolicyChange(std::shared_ptr<ScanOrchestrator> scanOrchestrator);

    /**
     * @brief Rescan if manager policy change from false to true.
     * This method is used to initialize the rescan dispatcher if manager is enabled.
     * if the manager scan is disable a elements will be removed from the inventory.
     *
     * @param scanOrchestrator Scan orchestrator.
     */
    void managerScanPolicyChange(std::shared_ptr<ScanOrchestrator> scanOrchestrator);

private:
    std::unique_ptr<RouterSubscriber> m_syscollectorDeltasSubscription;
    std::unique_ptr<RouterSubscriber> m_syscollectorRsyncSubscription;
    std::unique_ptr<RouterSubscriber> m_wdbAgentEventsSubscription;
    std::unique_ptr<PolicyManager> m_policyManager;
    std::shared_ptr<DatabaseFeedManager> m_databaseFeedManager;
    std::shared_ptr<IndexerConnector> m_indexerConnector;
    std::shared_ptr<SocketClient<Socket<OSPrimitives, NoHeaderProtocol>, EpollWrapper>> m_reportSocketClient;
    std::shared_ptr<ReportDispatcher> m_reportDispatcher;
    std::shared_ptr<Utils::RocksDBWrapper> m_stateDB;
    std::thread m_rebootThread;
    std::thread m_managerThread;
    std::atomic<bool> m_shouldStop {false};
    std::atomic<bool> m_shouldRescan {false};
    bool m_noWaitToStop {true};
    std::shared_ptr<DelayedEventDispatcher> m_delayedDispatcher;
    std::shared_mutex m_internalMutex;
    std::condition_variable m_retryWait;
    std::mutex m_retryMutex;
};

#endif // _VULNERABILITY_SCANNER_FACADE_HPP
